using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Project03
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        SpriteFont spriteFont;
        InputListener inputListener;

        private Vector2 screenDimension;
        private Texture2D xCoordinate;
        private Texture2D yCoordinate;
        private Vector2 rootCoordinate;
        private string infoString;
        private Vector2 infoPosition;

        //Objects
        private Object gun;
        private Object projectile;
        private Object target;
        private Object explosion;
        private Texture2D gunTexture;
        private Texture2D projectileTexture;
        private Texture2D targetTexture;
        private Texture2D explosionTexture;

        //Projectile path
        private Texture2D pathTexture;       
        private List<Vector2> pathList;

        //Data
        private Texture2D angleLine;
        private Texture2D wallLine;

        //Project-03
        private float correctAngle;
        private float currentAngle;        
        private float velocity;
        private float timer;
        private float distance;
        private float x;
        private float y;
        private const float g = 9.81f;

        private bool isStart;
        private bool isExplose;
        private bool isHit;
        

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            this.IsMouseVisible = true;
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            inputListener = new InputListener(this);
            Components.Add(inputListener);

            screenDimension = new Vector2(graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height);

            xCoordinate = CreateRectangle(900, 1, Color.White);
            yCoordinate = CreateRectangle(720, 1, Color.White);
            rootCoordinate = new Vector2(450, 450);
            infoPosition = new Vector2(950, 50);

            pathTexture = CreateRectangle(1, 1, Color.DarkRed);
            pathList = new List<Vector2>();

            angleLine = CreateRectangle(400, 1, Color.CornflowerBlue);
            wallLine = CreateRectangle(720, 1, Color.CornflowerBlue);

            //Project-03
            currentAngle = 0.45f;
            velocity = 100f;
            timer = 0;
            distance = 700f;

            isStart = false;
            isExplose = false;
            isHit = false;
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            spriteFont = Content.Load<SpriteFont>("gameFont");
            gunTexture = Content.Load<Texture2D>("gun");
            projectileTexture = Content.Load<Texture2D>("projectile");
            targetTexture = Content.Load<Texture2D>("target");
            explosionTexture = Content.Load<Texture2D>("explosion");

            gun = new Object(gunTexture, new Vector2(-395, 0));
            projectile = new Object(projectileTexture, new Vector2(-395, 0));
            target = new Object(targetTexture, new Vector2(395, 0));
            explosion = new Object(explosionTexture, new Vector2(-395, 0),1,12, 90, false);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (inputListener.isKeyDown(Keys.Escape))
                this.Exit();

            if (inputListener.isKeyPressed(Keys.Space))            
                isStart = !isStart;
            
            if (inputListener.isKeyPressed(Keys.Back))
            {
                //isStart = false;
                //isExplose = false;
                //timer = 0f;
                //pathList.Clear();
                Initialize();
            }
            if (isStart == false && timer == 0)
            {
                //Adjust velocity 
                if (inputListener.isKeyPressed(Keys.W) && velocity < 200)
                    velocity += 10f;
                if (inputListener.isKeyPressed(Keys.S) && velocity > 100)
                    velocity -= 10f;

                //Adjust target position
                if (inputListener.isKeyPressed(Keys.A) && target.Position.X > 195)
                {
                    target.Position -= new Vector2(10, 0);
                    explosion.Position -= new Vector2(10, 0);
                }
                if (inputListener.isKeyPressed(Keys.D) && target.Position.X < 395)
                {
                    target.Position += new Vector2(10, 0);
                    explosion.Position += new Vector2(10, 0);
                }

                //Adjust current angle
                if (inputListener.isKeyDown(Keys.Up))
                    currentAngle += 0.001f;
                if (inputListener.isKeyDown(Keys.Down))
                    currentAngle -= 0.001f;

                //Distance between gun and target
                distance = Math.Abs(gun.Position.X) + Math.Abs(target.Position.X);

                //Correct angle to hit t5arget
                correctAngle = ((float)Math.Asin(g * distance / (velocity * velocity)))/2;
            }

            if (isStart == true)
                timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

            //Projectile travel position
            x = (float)(velocity * Math.Cos(currentAngle) * timer);
            y = (float)((-velocity * Math.Sin(currentAngle))*timer + (g * timer * timer) / 2);
            projectile.Position = new Vector2(-395 + x, y);
            explosion.Position = projectile.Position;
            pathList.Add(projectile.Position);

           

            if (projectile.Position.Y > 0 || projectile.Position.X > 450)
            {
                isStart = false;
                isExplose = true;
                explosion.Update(gameTime);

                if (Math.Abs(projectile.Position.X - target.Position.X) <= 5)
                    isHit = true;
            }
            
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Gray);

            // TODO: Add your drawing code here
            spriteBatch.Begin();

            //Drawing coordinate
            spriteBatch.Draw(xCoordinate, rootCoordinate, null, Color.White,
                0f, new Vector2(rootCoordinate.X, 1), 1f, SpriteEffects.None, 0f);
            spriteBatch.Draw(yCoordinate, rootCoordinate, null, Color.White,
                MathHelper.PiOver2, new Vector2(rootCoordinate.Y, 1), 1f, SpriteEffects.None, 0f);
            
            //Drawing angle line and wall line
            spriteBatch.Draw(angleLine, gun.Position + rootCoordinate, null, Color.White,
                -currentAngle, new Vector2(angleLine.Width/2, angleLine.Height/2), 1f, SpriteEffects.None, 0f);
            spriteBatch.Draw(wallLine, new Vector2(450, 0) + rootCoordinate, null, Color.White,
                MathHelper.PiOver2, new Vector2(rootCoordinate.Y, 1), 1f, SpriteEffects.None, 0f);

            //Drawing game's info
            infoString = "Gun ( " + gun.Position.X + " , " + gun.Position.Y + " )";
            infoString += "\nProjectile ( " + projectile.Position.X.ToString("0") + " , " + (-projectile.Position.Y).ToString("0") + " )";
            infoString += "\nTarget ( " + target.Position.X + " , " + target.Position.Y + " )";
            infoString += "\n\nCorrect Gun Angle: " + MathHelper.ToDegrees(correctAngle) + "";
            infoString += "\nCurrent Gun Angle: " + MathHelper.ToDegrees(currentAngle) + "";
            infoString += "\n\nTarget Distance: " + distance + " m";
            infoString += "\n\nVelocity: " + velocity + " m/s";
            infoString += "\nTime: " + timer.ToString("0.0") + " s";
            spriteBatch.DrawString(spriteFont, infoString, infoPosition, Color.Black);

            //Drawing objects
            spriteBatch.Draw(gun.Texture, gun.Position + rootCoordinate, null, Color.White,
                -currentAngle, gun.Origin, 1f, SpriteEffects.None, 0f);
            foreach (Vector2 pathPosition in pathList)
                spriteBatch.Draw(pathTexture, pathPosition + rootCoordinate, Color.White);           
            
            if (isExplose == true)
                explosion.Draw(spriteBatch, rootCoordinate);
            else
                spriteBatch.Draw(projectile.Texture, projectile.Position + rootCoordinate, null, Color.White,
                0f, projectile.Origin, 1f, SpriteEffects.None, 0f);
            if (isHit == false)
                spriteBatch.Draw(target.Texture, target.Position + rootCoordinate, null, Color.White,
                    0f, target.Origin, 1f, SpriteEffects.None, 0f);
           
            spriteBatch.End();
            base.Draw(gameTime);
        }

        private Texture2D CreateRectangle(int width, int height, Color objColor)
        {
            Texture2D rectTexture = new Texture2D(GraphicsDevice, width, height, false, SurfaceFormat.Color);

            Color[] color = new Color[width * height];

            for (int i = 0; i < color.Length; i++)
                color[i] = objColor;

            rectTexture.SetData(color);

            return rectTexture;
        }
    }
}
